/*
 * Copyright (C) 2009 Kristopher T Babic
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses>.
 */

package edu.idp.client;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Vector;

// JPanel
/**
 *
 * @author Kristopher T Babic
 */
class BSlider extends java.awt.Component implements MouseListener, java.awt.event.MouseMotionListener {

    private static int WIDTH = 8;

    public static int HORIZONTAL = 0;
    public static int VERTICAL = 1;

    private double location = 0.0;

    private double maxVal = 0;
    private double curVal = 0;
    private double minVal = 0;

    private boolean initialized = false;
    private Vector changeListeners = null;

    private static double _defaultMin = 0.0;
    private static double _defaultMax = 100.0;
    private static double _defaultStart = 0.5;

    public BSlider() {
        this(_defaultMax);
    }

    public BSlider(double maxVal) {
        this(_defaultMin, maxVal);
    }

    public BSlider(double minVal, double maxVal) {

        this.addMouseListener(this);
        this.addMouseMotionListener(this);

        setMaximum(maxVal);
        setMinimum(minVal);
        setValue(getMaximum() / 2);
        initialized = true;

    }

    public void setMinimum(double minVal) {
        this.minVal = minVal;
    }

    public double getMinimum() {
        return this.minVal;
    }

    public void setMaximum(double maxVal) {
        this.maxVal = maxVal;
    }

    public double getMaximum() {
        return this.maxVal;
    }

    public void setValue(double newVal) {
        this.curVal = newVal;
        double diff = getMaximum() - getMinimum();
        double newDiff = newVal - getMinimum();

        setPercent(1 - ((diff - newDiff) / diff));

    }

    public double getValue() {
        return this.curVal;
    }

    private void setValueOnly(double newVal) {
        this.curVal = newVal;
    }

    private void setPercent(double location) {
        this.location = location;
        if (initialized)
            repaint();
    }

    public double getPercent() {
        return this.location;
    }

    public void paint(Graphics g) {

        java.awt.Rectangle bounds = getBounds();
        //g.setColor(Color.red);
        drawBar(g, bounds);
        drawPointer(g, bounds);

        double len = (double) (bounds.width - WIDTH - WIDTH);

        if (bounds.height >= 23) {
            drawBarLine(g, len, 23); //ounds, 23);
            if (bounds.height >= 35 && len >= 5)
                drawLabels(g, len, 35);
        }

    }

    private void drawLabels(Graphics g, double len, int height) {

        g.setColor(new Color(130, 130, 130));
        g.setFont(new Font("sansserif", Font.BOLD, 12));
        String start = "" + getMinimum();
        String end = "" + getMaximum();

        int startLoc = 0;
        if ((((double) start.length() * 8.0) / 2.0) > WIDTH)
            startLoc = 4;
        else
            startLoc = (int) ((double) WIDTH - ((double) start.length() * 8.0) / 2.0);

        int endLoc = 0;
        if ((((double) end.length() * 8.0) / 2.0) > WIDTH)
            endLoc = (int) ((len + 2.0 * (double) WIDTH) - (double) end.length() * 8.0);
        else
            endLoc = (int) (len + (double) WIDTH - ((double) end.length() * 8.0) / 2.0);

        g.drawChars(start.toCharArray(), 0, start.length(),
                    startLoc,
                    height);
//((((WIDTH-start.length())*7)/2))%WIDTH,
        g.drawChars(end.toCharArray(), 0, end.length(),
                    endLoc,
                    height);
//WIDTH + (int)len - ((end.length()*7)/2),

    }

    private void drawBarLine(Graphics g, double len, int height) {
        g.setColor(new Color(130, 130, 130));
//    double len = (double)(bounds.width - WIDTH - WIDTH);
        double bigwidth = len / 10.0;

        g.drawLine(WIDTH, height, WIDTH + (int) len, height);

        for (int i = 0; i <= 10; i++)
            g.drawLine(WIDTH + (int) ((double) i * bigwidth), height - 6, WIDTH + (int) ((double) i * bigwidth), height);

        double midwidth = bigwidth / 2.0;

        if (midwidth >= 2.0) {
            for (int i = 0; i < 20; i++) {
                if ((i % 10) != 0)
                    g.drawLine(WIDTH + (int) ((double) i * midwidth), height - 4, WIDTH + (int) ((double) i * midwidth), height);
            }
        }

        double smallwidth = bigwidth / 10.0;

        if (smallwidth >= 2.0) {
            for (int i = 0; i < 100; i++) {
                if (((i % 10) != 0) && (i % 5 != 0))
                    g.drawLine(WIDTH + (int) ((double) i * smallwidth), height - 2, WIDTH + (int) ((double) i * smallwidth), height);
            }
        }
    }

    private void drawBar(Graphics g, java.awt.Rectangle bounds) {
        g.setColor(new Color(130, 130, 130));
        g.drawLine(WIDTH, 2, WIDTH, 7);
        g.drawLine(WIDTH, 2, bounds.width - WIDTH, 2);
        g.drawLine(bounds.width - WIDTH, 2, bounds.width - WIDTH, 7);
        g.drawLine(WIDTH, 7, bounds.width - WIDTH, 7);

        g.setColor(new Color(170, 170, 170));
        g.drawLine(WIDTH + 1, 3, WIDTH + 1, 6);
        g.drawLine(WIDTH + 1, 3, bounds.width - WIDTH - 1, 3);

        g.setColor(Color.white);
        g.drawLine(WIDTH + 1, 8, bounds.width - WIDTH + 1, 8);
        g.drawLine(bounds.width - WIDTH + 1, 3, bounds.width - WIDTH + 1, 8);

        /*    g.drawLine(WIDTH, 7, bounds.width-WIDTH, bounds.height/2);
           g.setColor(Color.darkGray);
           g.drawLine(WIDTH, bounds.height/2+1, bounds.width-WIDTH, bounds.height/2+1);

           for (int i = 0; i <= (bounds.width-WIDTH); i+=((bounds.width-(2*WIDTH))/10))
             g.drawLine(i+WIDTH, bounds.height/2 - 3, i+WIDTH, bounds.height/2+3);
        */
    }

    private void drawPointer(Graphics g, java.awt.Rectangle bounds) {
        int x = (int) (location * (double) (bounds.width - (2 * WIDTH))) + WIDTH;


        g.setColor(Color.black);
        g.drawLine(x - 5, 0, x + 5, 0);
        g.drawLine(x - 6, 1, x - 6, 7);
        g.drawLine(x + 6, 1, x + 6, 7);
        g.drawLine(x - 6, 8, x, 14);
        g.drawLine(x + 6, 8, x, 14);
        g.setColor(new Color(160, 160, 200));
        int xpts[] = new int[5];
        xpts[0] = x - 5;
        xpts[1] = x + 6;
        xpts[2] = x + 6;
        xpts[3] = x;
        xpts[4] = x - 6;
        int ypts[] = new int[5];
        ypts[0] = 1;
        ypts[1] = 1;
        ypts[2] = 7;
        ypts[3] = 14;
        ypts[4] = 7;
        g.fillPolygon(xpts, ypts, 5);

        g.setColor(Color.darkGray);

        g.drawLine(x - 2, 4, x - 2, 4);
        g.drawLine(x + 3, 4, x + 3, 4);
        g.drawLine(x - 2, 8, x - 2, 8);
        g.drawLine(x + 3, 8, x + 3, 8);

        g.setColor(Color.lightGray);

        g.drawLine(x - 3, 3, x - 3, 3);
        g.drawLine(x + 2, 3, x + 2, 3);
        g.drawLine(x - 3, 7, x - 3, 7);
        g.drawLine(x + 2, 7, x + 2, 7);

        g.drawLine(x - 5, 1, x - 5, 7);
        g.drawLine(x - 5, 1, x + 5, 1);

/*
    g.setColor(Color.white);
    g.drawLine(x, 0, x+WIDTH-1, 0);
    g.drawLine(x, 0, x, bounds.height-1);
    g.drawLine(x+1, 1, x+WIDTH-2, 1);
    g.drawLine(x+1, 1, x+1, bounds.height-2);

    g.setColor(Color.black);
    g.drawLine(x+1, bounds.height-1, x+WIDTH, bounds.height-1);
    g.drawLine(x+WIDTH, 0, x+WIDTH, bounds.height-1);
    g.setColor(Color.darkGray);
    g.drawLine(x+2, bounds.height-2, x+WIDTH-1, bounds.height-2);
    g.drawLine(x+WIDTH-1, 1, x+WIDTH-1, bounds.height-2);

    g.setColor(new Color(12632256));
      //g.fillRect(x+3, 2, x+WIDTH-2, bounds.height-3);
    g.fillRect(x+2, 2, WIDTH-3, bounds.height-5);
      //g.fillRect((int)((location) * (double)(bounds.width-5)), 0, 5, bounds.height);
*/
    }

    private void calculateLocation(int x) {
        java.awt.Rectangle bounds = this.getBounds();
        bounds.width -= 2 * WIDTH;
        x -= WIDTH;

        double newLocation = 1.0 - (((double) bounds.width - x) / ((double) (bounds.width)));

        if (newLocation > 1.0)
            newLocation = 1.0;
        else if (newLocation < 0.0)
            newLocation = 0.0;

        setPercent(newLocation);
        setValueOnly(getMinimum() + getPercent() * (getMaximum() - getMinimum()));
        //System.out.println(getValue());
    }

    public java.awt.Dimension getMinimumSize() {
        return new java.awt.Dimension(100, 30);
    }

    /**
     * **********************
     * mouse handling
     * ***********************
     */
    protected void processMouseEvent(MouseEvent e) {
        int id = e.getID();

        if (!this.contains(e.getPoint()))
            return;

        if (id == MouseEvent.MOUSE_CLICKED ||
                id == MouseEvent.MOUSE_PRESSED ||
                id == MouseEvent.MOUSE_DRAGGED) {
            calculateLocation(e.getPoint().x);
            fireChangeEvent(new ChangeEvent(this));
        }
    }

    public void mouseDragged(MouseEvent e) {
        if (!this.contains(e.getPoint()))
            return;
        calculateLocation(e.getPoint().x);
        fireChangeEvent(new ChangeEvent(this));
    }

    public void mouseMoved(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    /**
     * *****************************************
     * methods for adding and manipulating ChangeEvents
     * ******************************************
     */
    public synchronized void addChangeListener(ChangeListener cl) {
        if (changeListeners == null)
            changeListeners = new Vector();
        changeListeners.addElement(cl);
    }

    public synchronized void removeChangeListener(ChangeListener cl) {
        if (changeListeners != null && cl != null)
            changeListeners.removeElement(cl);
    }

    protected void fireChangeEvent(ChangeEvent ce) {
        if (changeListeners == null)
            return;
        Vector targets;
        synchronized (this) {
            targets = (Vector) changeListeners.clone();
        }

        for (int i = 0; i < targets.size(); i++) {
            ChangeListener target = (ChangeListener) targets.elementAt(i);
            target.stateChanged(ce);
        }

    }


}

